package com.panopset.flywheel.gui;

import static com.panopset.Util.*;
import static com.panopset.UtilIO.*;

import java.awt.BorderLayout;
import java.awt.FlowLayout;
import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.io.File;

import javax.swing.JButton;
import javax.swing.JScrollPane;
import javax.swing.JSplitPane;

import com.panopset.AbstractApplication;
import com.panopset.centralen.resource.PersistentContainer;
import com.panopset.flywheel.Flywheel;
import com.panopset.gui.TButton;
import com.panopset.gui.TPanel;
import com.panopset.gui.container.PanDirectory;
import com.panopset.gui.container.PanFile;

/**
 *
 * @author Karl Dinwiddie
 */
public final class FlywheelMainApplicationPanel {

    /**
     * Main panel.
     */
    private TPanel panel;

    /**
     * Script file container.
     */
    private ScriptFileContainer scriptFileContainer;

    /**
     * @return ScriptFileContainer.
     */
    private ScriptFileContainer getScriptFileContainer() {
        if (scriptFileContainer == null) {
            scriptFileContainer = new ScriptFileContainer();
        }
        return scriptFileContainer;
    }

    /**
     * @return Main panel.
     */
    public TPanel getPanel() {
        if (panel == null) {
            panel = new TPanel.Builder().layout(new BorderLayout()).construct();
            panel.add(BorderLayout.NORTH, assembleNorthLayout());
            panel.add(BorderLayout.CENTER, getWorkBench());
        }
        return panel;
    }

    /**
     * North layout grid rows is 5.
     */
    private static final int NORTH_LAYOUT_GRID_ROWS = 5;

    /**
     * North layout grid cols is 1.
     */
    private static final int NORTH_LAYOUT_GRID_COLS = 1;

    /**
     * @return North panel.
     */
    private TPanel assembleNorthLayout() {
        final TPanel rtn = new TPanel.Builder().layout(
                new GridLayout(NORTH_LAYOUT_GRID_ROWS, NORTH_LAYOUT_GRID_COLS))
                .construct();
        rtn.add(getScriptFileSelector().getPanel());
        rtn.add(getTargetDirectorySelector().getPanel());
        rtn.add(getPropertiesFileSelector().getPanel());
        TPanel buttons = new TPanel(new FlowLayout());
        buttons.add(getLoadButton());
        buttons.add(getSaveButton());
        buttons.add(getStepButton());
        buttons.add(getExecButton());
        getExecButton().setEnabled(false);
        getStepButton().setEnabled(false);
        rtn.add(buttons);
        TPanel cbtns = new TPanel(new FlowLayout());
        for (final Commenum commenum : Commenum.values()) {
            JButton btn = commenum.createButton();
            btn.addActionListener(new ActionListener() {

                @Override
                public void actionPerformed(final ActionEvent e) {
                    userSelect(commenum.getPrototype());
                }

            });
            cbtns.add(btn);
        }
        JButton btn = new TButton("clear");
        btn.addActionListener(new ActionListener() {

            @Override
            public void actionPerformed(final ActionEvent e) {
                userClear();
            }

        });
        cbtns.add(btn);
        rtn.add(cbtns);
        return rtn;
    }

    /**
     * User select.
     *
     * @param prototype
     *            Selected prototype.
     */
    void userSelect(final String prototype) {
        getScriptFileContainer().getTextArea().append(prototype);
    }

    /**
     * User clear.
     */
    void userClear() {
        getScriptFileContainer().getTextArea().setText("");
    }

    /**
     * User step.
     */
    private void step() {
        getScriptFileContainer().step();
    }

    /**
     * User exec.
     */
    private void exec() {
        load();
        getScriptFileContainer().exec();
    }

    /**
     * User save.
     */
    private void save() {
        getScriptFileContainer().save();
    }

    /**
     * User quit.
     */
    public void quit() {
        getScriptFileContainer().quit();
    }

    /**
     * Load script.
     */
    public void load() {
        File scriptFile = getScriptFileSelector().getFile();
        File target = getTargetDirectorySelector().getFile();
        File properties = getPropertiesFileSelector().getFile();

        if (validateFile(scriptFile) && validateDirectory(target)) {
            getScriptFileContainer().setFlywheel(
                    new Flywheel.Builder().file(scriptFile)
                    .targetDirectory(target).properties(properties)
                    .construct());
            getScriptFileContainer().load();
            getExecButton().setEnabled(true);
            getStepButton().setEnabled(true);
        }
    }

    /**
     * Exec button.
     */
    private TButton execButton;

    /**
     * @return Exec button.
     */
    private TButton getExecButton() {
        if (execButton == null) {
            execButton = new TButton(x("Exec"), KeyEvent.VK_E,
                    "Execute template", new ActionListener() {

                        @Override
                        public void actionPerformed(final ActionEvent e) {
                            exec();
                        }
                    });
            execButton.setEnabled(false);
        }
        return execButton;
    }

    /**
     * Step button.
     */
    private TButton stepButton;

    /**
     * @return Step button.
     */
    private TButton getStepButton() {
        if (stepButton == null) {
            stepButton = new TButton(x("Step"), KeyEvent.VK_S,
                    x("Execute template commands one at a time") + ".",
                    new ActionListener() {

                        @Override
                        public void actionPerformed(final ActionEvent e) {
                            step();
                        }
                    });
            stepButton.setEnabled(false);
        }
        return stepButton;
    }

    /**
     * Load button.
     */
    private TButton loadButton;

    /**
     * @return Load button.
     */
    private TButton getLoadButton() {
        if (loadButton == null) {
            loadButton = new TButton(x("Load"), KeyEvent.VK_L, "Load template",
                    new ActionListener() {

                        @Override
                        public void actionPerformed(final ActionEvent e) {
                            load();
                        }
                    });
        }
        return loadButton;
    }

    /**
     * Save button.
     */
    private TButton saveButton;

    /**
     * @return save button.
     */
    private TButton getSaveButton() {
        if (saveButton == null) {
            saveButton = new TButton(x("Save"), KeyEvent.VK_S,
                    x("Save templates"), new ActionListener() {

                        @Override
                        public void actionPerformed(final ActionEvent e) {
                            save();
                        }
                    });
        }
        return saveButton;
    }

    /**
     * Properties file selector.
     */
    private PanFile propertiesFileSelector;

    /**
     * @return Properties file selector.
     */
    private PanFile getPropertiesFileSelector() {
        if (propertiesFileSelector == null) {
            propertiesFileSelector = new PanFile(
                    x("Properties (optional)"),
                    x("optional properties file")
                            + "."
                            + x("All properties available to variable commands")
                            + ".");
        }
        return propertiesFileSelector;
    }

    /**
     * Target directory selector.
     */
    private PanDirectory targetDirectorySelector;

    /**
     * @return Target directory selector.
     */
    private PanDirectory getTargetDirectorySelector() {
        if (targetDirectorySelector == null) {
            targetDirectorySelector = new PanDirectory(x("Target"),
                    x("target directory")
                            + "."
                            + x("All output will be relative to this directory"
                                    + "."));
        }
        return targetDirectorySelector;
    }

    /**
     * Script file selector.
     */
    private PanFile scriptFileSelector;

    /**
     * @return Script file selector.
     */
    private PanFile getScriptFileSelector() {
        if (scriptFileSelector == null) {
            scriptFileSelector = new PanFile(x("Script File"),
                    x("Primary script file."));
        }
        return scriptFileSelector;
    }

    /**
     * Default divider location.
     */
    private static final int DEFAULT_DIVIDER_LOCATION = 300;

    /**
     * Divider location.
     */
    private PersistentContainer dividerLocation;

    /**
     * @return Divider location.
     */
    private PersistentContainer getDividerLocation() {
        if (dividerLocation == null) {
            dividerLocation = new PersistentContainer(""
                    + DEFAULT_DIVIDER_LOCATION) {

                @Override
                protected ValueMirror createValueMirror() {
                    return new PersistentContainer.ValueMirror() {

                        @Override
                        public void setValue(final String newValue) {
                            getWorkBench().setDividerLocation(
                                    Integer.parseInt(newValue));
                        }

                        @Override
                        public String getValue() {
                            return "" + getWorkBench().getDividerLocation();
                        }
                    };
                }

                @Override
                protected boolean isValid(final String valueToCheck) {
                    if (valueToCheck == null) {
                        return false;
                    }
                    try {
                        Integer.parseInt(valueToCheck);
                    } catch (final NumberFormatException ex) {
                        return false;
                    }
                    return true;
                }

            };
            AbstractApplication.add(dividerLocation);
        }
        return dividerLocation;
    }

    /**
     * Workbench.
     */
    private JSplitPane workBench;

    /**
     * @return workbench.
     */
    public JSplitPane getWorkBench() {
        if (workBench == null) {
            workBench = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT);
            workBench.setDividerLocation(Integer.parseInt(getDividerLocation()
                    .getValue()));
            workBench.setOneTouchExpandable(true);
            workBench.add(new JScrollPane(getScriptFileContainer()
                    .getTextArea()));
            workBench.add(getScriptFileContainer().getInfrastructure()
                    .getPanel());
        }
        return workBench;
    }
}
